package NIO.none_blocking;
/*
 * @Author  Wrial
 * @Date Created in 20:52 2020/4/11
 * @Description
 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

public class NoneBlockingClient {
    public static void main(String[] args) throws IOException {
        final NoneBlockingClient client = new NoneBlockingClient(8090);
        Thread thread = new Thread(() -> {
            try {
                client.transMsgFromConsoleToSendBuffer();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        thread.start();
        client.talk();

    }
    private SocketChannel socketChannel = null;
    private int port;
    private Charset charset;
    private Selector selector;
    private static ByteBuffer sendBuffer = ByteBuffer.allocate(1024);
    private static ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);

    public NoneBlockingClient(int port) throws IOException {
        this.port = port;
        charset = Charset.forName("UTF-8");
        socketChannel = SocketChannel.open();
        // 连接
        socketChannel.socket().connect(new InetSocketAddress("localhost", port));
        // 非阻塞
        socketChannel.configureBlocking(false);
        // 在选择器进行事件的注册
        System.out.println("client connect success  ");
        selector = Selector.open();
    }

    private void talk()  {
        try {
            socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
            while (selector.select() > 0) {
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> it = selectionKeys.iterator();
                while (it.hasNext()) {
                    SelectionKey selectionKey = it.next();
                    it.remove();
                    try {
                        handle(selectionKey);
                    } catch (IOException e) {
                        e.printStackTrace();
                        try {
                            if (selectionKey!=null){
                                selectionKey.cancel();
                                selectionKey.channel().close();
                            }
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 用完一定要关闭channel
            try {
                socketChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void handle(SelectionKey selectionKey) throws IOException {
        if (selectionKey.isReadable()) {
            receive(selectionKey);
        }
        if (selectionKey.isWritable()) {
            send(selectionKey);
        }
    }

    private void send(SelectionKey selectionKey) throws IOException {
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        synchronized (sendBuffer){
            sendBuffer.flip();
            socketChannel.write(sendBuffer);
            sendBuffer.compact();
        }
    }

    private void receive(SelectionKey selectionKey) throws IOException {
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        socketChannel.read(receiveBuffer);
        receiveBuffer.flip();
        String receiveData = decode(receiveBuffer);

        if (receiveData.indexOf("\n")==-1) return;

        String outputData = receiveData.substring(0, receiveData.indexOf("\n")+1);
        System.out.println("receive data : " + outputData);
        if (outputData.equals("echo : " + "end\r\n")){
            selectionKey.channel();
            socketChannel.close();
            System.out.println("关闭和服务器的连接");
            selector.close();
            System.exit(0);
        }
        ByteBuffer temp = encode(outputData);
        receiveBuffer.position(temp.limit());
        receiveBuffer.compact();
    }

    private ByteBuffer encode(String outputData) {
        return charset.encode(outputData);
    }

    private String decode(ByteBuffer receiveBuffer) {
        return charset.decode(receiveBuffer).toString();
    }

    private void transMsgFromConsoleToSendBuffer() throws IOException {

        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        String msg = null;
        while ((msg = bufferedReader.readLine()) != null) {
            synchronized (sendBuffer) {
                sendBuffer.put(charset.encode(msg + "\r\n"));
            }
            if (msg.equals("end")) {
                System.out.println("退出连接");
                break;
            }
        }

    }




}
